/*
 * Copyright (c) 2021-2021, THEWON
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-10-09     THEWON       first version
 * 2021-10-11     THEWON       add h file; add public reference api
 * 2021-10-13     THEWON       add -a argument, list all objects
 * 2021-10-14     THEWON       add -h argument, show usage
 */

#include <rthw.h>
#include <rtthread.h>
#include <stdio.h>
#include <stdlib.h>

#include <string.h>
#include <ctype.h>

#ifdef RT_USING_FINSH
#include <finsh.h>
#endif

static const char _hex_tbl[] = "0123456789ABCDEF";
static int group_size = 4;
static int line_size = 32;

static inline void printMemUsage(const char *cmd)
{
    rt_kprintf("Usage: %s [-glh] <start address> <end address>\r\n"
            "         <start address>            start address of memory[hex]\r\n"
            "         <end address>              end address of memory[hex]\r\n"
            "         [-g <group size>]          group size[4]\r\n"
            "         [-l <line size>]           line size[32]\r\n"
            "         [-h]                       show current help\r\n"
            , cmd);
}

static inline void printObjectUsage(const char *cmd)
{
    rt_kprintf("Usage: %s [-ah] <object name>\r\n"
            "         <object name>              show object details\r\n"
            "         [-a]                       show all objects details\r\n"
            "         [-h]                       show current help\r\n"
            , cmd);
}

static unsigned char tohex(char ch)
{
    int i;
    for (i = 0; i < 16; i++) {
        if (_hex_tbl[i] == ch) {
            return i & 0xF;
        }
    }
    return 0;
}

static void printMem(unsigned int sta, unsigned int end, int g_size, int l_size)
{
    int i;
    unsigned int _memptr;
    unsigned char ch;

    if ((end - sta + 1) < l_size) {
        l_size = end - sta + 1;
    }
    for (_memptr = sta; _memptr <= end; _memptr += l_size) {
        rt_kprintf("0x%08X   ", _memptr);
        for (i = 0; i < l_size; i++) {
            if (i%g_size == 0) {
                rt_kprintf(" ");
            }
            if ((_memptr+i) > end){
                rt_kprintf("  ");
            } else {
                rt_kprintf("%02X", *((unsigned char*)(_memptr+i)));
            }
        }
        rt_kprintf("    ");
        for (i = 0; i < l_size; i++) {
            if ((_memptr+i) > end){
                break;
            }
            ch = *((unsigned char*)(_memptr+i));
            if (((ch & 0x80) == 0) && isprint(ch)) {
                rt_kprintf("%c", ch);
            } else {
                rt_kprintf(".");
            }
        }
        rt_kprintf("\n");
    }
}

void od_set_group_size(int group_sz)
{
    group_size = group_sz;
}

void od_set_line_size(int line_sz)
{
    line_size = line_sz;
}

void od_mem(unsigned int start_addr, unsigned int end_addr)
{
    printMem(start_addr, end_addr, group_size, line_size);
}

static int cmd_od_mem(int argc, char *argv[])
{
    int arg_c = argc-1;
    char **arg_v = &argv[1];
    char *_start = 0, *_end = 0;
    unsigned int start_addr = 0, end_addr = 0;
    int i, help = 0;

    if (arg_c < 2) {
        printMemUsage(argv[0]);
        return 0;
    }

    while (arg_c > 0) {
        if (strcmp(arg_v[0], "-g") == 0) {
            group_size = atoi(arg_v[1]);
            arg_c--; arg_v++;
        } else if (strcmp(arg_v[0], "-l") == 0) {
            line_size = atoi(arg_v[1]);
            arg_c--; arg_v++;
        } else if (strcmp(arg_v[0], "-h") == 0) {
            help = 1;
        } else {
            if (_start == 0) {
                _start = arg_v[0];
            } else {
                _end = arg_v[0];
            }
        }
        arg_c--; arg_v++;
    }

    if (help == 1) {
        printMemUsage(argv[0]);
        return 0;
    }

    if (_start == 0 || _end == 0) {
        printMemUsage(argv[0]);
        return -1;
    }
    if (_start[0] == '0' && (_start[1] == 'x' || _start[1] == 'X')) {
        _start += 2;
    }
    if (_end[0] == '0' && (_end[1] == 'x' || _end[1] == 'X')) {
        _end += 2;
    }

    start_addr = 0;
    for (i = 0; i < strlen(_start); i++) {
        start_addr <<= 4;
        if (!isxdigit(_start[i])) {
            printMemUsage(argv[0]);
            return -1;
        }
        start_addr |= tohex(toupper(_start[i]));
    }

    end_addr = 0;
    for (i = 0; i < strlen(_end); i++) {
        end_addr <<= 4;
        if (!isxdigit(_end[i])) {
            printMemUsage(argv[0]);
            return -1;
        }
        end_addr |= tohex(toupper(_end[i]));
    }

    printMem(start_addr, end_addr, group_size, line_size);

    return 0;
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(cmd_od_mem, od_mem, show memory value in hex);
#endif

rt_inline void object_split(int len)
{
    while (len--) rt_kprintf("-");
}

int od_thread(char *name)
{
    unsigned int start_addr = 0, end_addr = 0;
    const char *item_title = "thread";
    struct rt_object_information *info;
    rt_list_t *list;
    struct rt_object *obj;
    struct rt_thread *thread;
    struct rt_list_node *prev, *next;

    if (name == RT_NULL) {
        rt_kprintf("%-*.s      addr      pri   init pri    flags     stack addr   stack size       sp       tick   timer\n", RT_NAME_MAX, item_title);
        object_split(RT_NAME_MAX);
        rt_kprintf(" | ---------- | --- | -------- | -------- | ---------- | ---------- | ---------- | ---- | ----------\n");

        info = rt_object_get_information(RT_Object_Class_Thread);
        list = &info->object_list;

        rt_list_for_each_safe(prev, next, list) {
            obj = rt_list_entry(prev, struct rt_object, list);
            thread = (struct rt_thread *)obj;
            rt_kprintf("%-*.*s   0x%08X   %3d     %3d        0x%02X     0x%08X   0x%08X   0x%08X    %3d   0x%08X\n", RT_NAME_MAX, RT_NAME_MAX, 
                        thread->name, thread, thread->current_priority, thread->init_priority, thread->flags, thread->stack_addr, thread->stack_size, thread->sp, thread->remaining_tick, &thread->thread_timer);
        }

        return 0;
    }

    thread = (struct rt_thread *)rt_object_find(name, RT_Object_Class_Thread);
    if (thread == RT_NULL) {
        rt_kprintf("thread %s not found\n", name);
        return -1;
    }

    start_addr = (unsigned int)thread;
    end_addr = start_addr + sizeof(struct rt_thread) - 1;
    printMem(start_addr, end_addr, group_size, line_size);
    rt_kprintf("\n");

    rt_kprintf("name:           %s\n", thread->name);
    rt_kprintf("  type:         0x%02X\n", thread->type);
    rt_kprintf("  flag:         0x%02X\n", thread->flags);
    rt_kprintf("  prev object:  %P\n", thread->list.prev);
    rt_kprintf("  next object:  %P\n", thread->list.next);
    rt_kprintf("  prev thread:  %P\n", thread->tlist.prev);
    rt_kprintf("  next thread:  %P\n", thread->tlist.next);
    rt_kprintf("  sp:           %P\n", thread->sp);
    rt_kprintf("  entry:        %P\n", thread->entry);
    rt_kprintf("  parameter:    %P\n", thread->parameter);
    rt_kprintf("  stack addr:   %P\n", thread->stack_addr);
    rt_kprintf("  stack size:   0x%08X\n", thread->stack_size);
    rt_kprintf("  error:        %d\n", thread->error);
    rt_kprintf("  stat:         0x%02X\n", thread->stat);
    rt_kprintf("  curr prior:   %d\n", thread->current_priority);
    rt_kprintf("  init prior:   %d\n", thread->init_priority);
#if defined(RT_USING_EVENT)
    /* thread event */
    rt_kprintf("  event set:    0x%08X\n", thread->event_set);
    rt_kprintf("  event info:   0x%02X\n", thread->event_info);
#endif
    rt_kprintf("  init tick:    %d\n", thread->init_tick);
    rt_kprintf("  left tick:    %d\n", thread->remaining_tick);

    return 0;
}

int od_all_thread()
{
    struct rt_object_information *info;
    rt_list_t *header, *list;
    struct rt_object *obj;
    struct rt_list_node *prev, *next;
    struct rt_thread *thread, *thread_t;
    char *error, *status, *stat;

    info = rt_object_get_information(RT_Object_Class_Thread);
    header = &info->object_list;

    rt_kprintf("class:         Thread\n");
    rt_kprintf("header:        %P\n", header);
    rt_kprintf("\n");

    list = header;
    rt_list_for_each_safe(prev, next, list) {
        obj = rt_list_entry(prev, struct rt_object, list);
        thread = (struct rt_thread *)obj;
        rt_kprintf("thread:         %P : %s\n", thread, thread->name);
        rt_kprintf("  type:         0x%02X : %s\n", thread->type, (thread->type & RT_Object_Class_Static) ? "static" : "dynamic");
        thread_t = (struct rt_thread *)((unsigned int)thread->list.prev - (unsigned int)(&((struct rt_thread *)0)->list));
        if (thread->list.prev == header) {
        rt_kprintf("  prev thread:  %P : %s\n", header, "none");
        } else {
        rt_kprintf("  prev thread:  %P : %s\n", thread_t, thread_t->name);
        }
        rt_kprintf("  sp:           %P\n", thread->sp);
        rt_kprintf("  entry:        %P\n", thread->entry);
        rt_kprintf("  parameter:    %P\n", thread->parameter);
        rt_kprintf("  stack addr:   %P\n", thread->stack_addr);
        rt_kprintf("  stack size:   0x%08X\n", thread->stack_size);

        switch (thread->error) {
        case RT_EOK:
            error = "no error";
        break;
        case RT_ERROR:
            error = "generic error";
        break;
        case RT_ETIMEOUT:
            error = "Timed out";
        break;
        case RT_EFULL:
            error = "resource full";
        break;
        case RT_EEMPTY:
            error = "resource empty";
        break;
        case RT_ENOMEM:
            error = "No memory";
        break;
        case RT_ENOSYS:
            error = "No system";
        break;
        case RT_EBUSY:
            error = "Busy";
        break;
        case RT_EIO:
            error = "IO error";
        break;
        case RT_EINTR:
            error = "Interrupted";
        break;
        case RT_EINVAL:
            error = "Invalid argument";
        break;
        default:
        break;
        }
        rt_kprintf("  error:        %d : %s\n", thread->error, error);

        if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE) {
            status = "closed";
        } else if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_RUNNING) {
            status = "running";
        } else if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND) {
            status = "suspend";
        } else if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY) {
            status = "ready";
        } else {
            status = "init";
        }
        if ((thread->stat & RT_THREAD_STAT_SIGNAL_MASK) == RT_THREAD_STAT_SIGNAL_PENDING) {
            stat = "signal pending";
        } else if ((thread->stat & RT_THREAD_STAT_SIGNAL_MASK) == RT_THREAD_STAT_SIGNAL_WAIT) {
            stat = "signal wait";
        } else if ((thread->stat & RT_THREAD_STAT_SIGNAL_MASK) == RT_THREAD_STAT_SIGNAL_READY) {
            stat = "signal ready";
        } else if ((thread->stat & RT_THREAD_STAT_SIGNAL_MASK) == RT_THREAD_STAT_SIGNAL) {
            stat = "signal hold";
        } else if ((thread->stat & RT_THREAD_STAT_YIELD_MASK) == RT_THREAD_STAT_YIELD) {
            stat = "yield";
        } else {
            stat = "no signal";
        }
        rt_kprintf("  stat:         0x%02X : %s | %s\n", thread->stat, status, stat);

        rt_kprintf("  curr prior:   %d\n", thread->current_priority);
        rt_kprintf("  init prior:   %d\n", thread->init_priority);
#if defined(RT_USING_EVENT)
        /* thread event */
        rt_kprintf("  event set:    0x%08X\n", thread->event_set);
        rt_kprintf("  event info:   0x%02X\n", thread->event_info);
#endif
        rt_kprintf("  init tick:    %d\n", thread->init_tick);
        rt_kprintf("  left tick:    %d\n", thread->remaining_tick);
        rt_kprintf("\n");
    }

    return 0;
}

static int cmd_od_thread(int argc, char *argv[])
{
    int arg_c = argc-1;
    char **arg_v = &argv[1];
    int all = 0, help = 0;
    char *name = RT_NULL;

    while(arg_c > 0){
        if(strcmp(arg_v[0], "-a") == 0){
            all = 1;
        } else if(strcmp(arg_v[0], "-h") == 0){
            help = 1;
        }else{
            name = arg_v[0];
        }
        arg_c--; arg_v++;
    }

    if (help == 1) {
        printObjectUsage(argv[0]);
        return 0;
    }
    if (all == 1) {
        return od_all_thread();
    }

    return od_thread(name);
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(cmd_od_thread, od_thread, dump thread);
#endif

#ifdef RT_USING_SEMAPHORE
int od_sem(char *name)
{
    unsigned int start_addr = 0, end_addr = 0;
    const char *item_title = "sem";
    struct rt_object_information *info;
    rt_list_t *list;
    struct rt_object *obj;
    struct rt_list_node *prev, *next;
    struct rt_semaphore *sem;

    if (name == RT_NULL) {
        rt_kprintf("%-*.s      addr      value\n", RT_NAME_MAX, item_title);
        object_split(RT_NAME_MAX);
        rt_kprintf(" | ---------- | -----\n");

        info = rt_object_get_information(RT_Object_Class_Semaphore);
        list = &info->object_list;

        rt_list_for_each_safe(prev, next, list) {
            obj = rt_list_entry(prev, struct rt_object, list);
            sem = (struct rt_semaphore *)obj;
            rt_kprintf("%-*.*s   0x%08X   %5d\n", RT_NAME_MAX, RT_NAME_MAX, 
                        sem->parent.parent.name, sem, sem->value);
        }
        return 0;
    }

    sem = (struct rt_semaphore *)rt_object_find(name, RT_Object_Class_Semaphore);
    if (sem == RT_NULL) {
        rt_kprintf("sem %s not found\n", name);
        return -1;
    }

    start_addr = (unsigned int)sem;
    end_addr = start_addr + sizeof(struct rt_semaphore) - 1;
    printMem(start_addr, end_addr, group_size, line_size);
    rt_kprintf("\n");

    rt_kprintf("name:           %s\n", sem->parent.parent.name);
    rt_kprintf("  type:         0x%02X\n", sem->parent.parent.type);
    rt_kprintf("  flag:         0x%02X\n", sem->parent.parent.flag);
    rt_kprintf("  prev object:  %P\n", sem->parent.parent.list.prev);
    rt_kprintf("  next object:  %P\n", sem->parent.parent.list.next);
    rt_kprintf("  prev suspend: %P\n", sem->parent.suspend_thread.prev);
    rt_kprintf("  next suspend: %P\n", sem->parent.suspend_thread.next);
    rt_kprintf("  value:        0x%04X\n", sem->value);

    return 0;
}

int od_all_sem()
{
    struct rt_object_information *info;
    rt_list_t *header, *list;
    struct rt_object *obj;
    struct rt_list_node *prev, *next;
    struct rt_semaphore *sem, *sem_t;
    struct rt_thread *thread_t;

    info = rt_object_get_information(RT_Object_Class_Semaphore);
    header = &info->object_list;

    rt_kprintf("class:         Semaphore\n");
    rt_kprintf("header:        %P\n", header);
    rt_kprintf("\n");

    list = header;
    rt_list_for_each_safe(prev, next, list) {
        obj = rt_list_entry(prev, struct rt_object, list);
        sem = (struct rt_semaphore *)obj;
        rt_kprintf("semaphore:      %P : %s\n", sem, sem->parent.parent.name);
        rt_kprintf("  type:         0x%02X : %s\n", sem->parent.parent.type, (sem->parent.parent.type & RT_Object_Class_Static) ? "static" : "dynamic");
        rt_kprintf("  flag:         0x%02X : %s\n", sem->parent.parent.flag, (sem->parent.parent.flag & RT_IPC_FLAG_PRIO) ? "PRIO" : "FIFO");
        sem_t = (struct rt_semaphore *)((unsigned int)sem->parent.parent.list.prev - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (sem->parent.parent.list.prev == header) {
        rt_kprintf("  prev sem:     %P : %s\n", header, "none");
        } else {
        rt_kprintf("  prev sem:     %P : %s\n", sem_t, sem_t->parent.parent.name);
        }
        sem_t = (struct rt_semaphore *)((unsigned int)sem->parent.parent.list.next - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (sem->parent.parent.list.next == header) {
        rt_kprintf("  next sem:     %P : %s\n", header, "none");
        } else {
        rt_kprintf("  next sem:     %P : %s\n", sem_t, sem_t->parent.parent.name);
        }
        
        if (sem->parent.suspend_thread.prev != &sem->parent.suspend_thread) {
        thread_t = (struct rt_thread *)((unsigned int)sem->parent.suspend_thread.prev - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  prev suspend: %P : %s\n", thread_t, thread_t->name);
        }
        if (sem->parent.suspend_thread.next != &sem->parent.suspend_thread) {
        thread_t = (struct rt_thread *)((unsigned int)sem->parent.suspend_thread.next - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  next suspend: %P : %s\n", thread_t, thread_t->name);
        }
        rt_kprintf("  value:        0x%04X\n", sem->value);
        rt_kprintf("\n");
    }
    return 0;
}

static int cmd_od_sem(int argc, char *argv[])
{
    int arg_c = argc-1;
    char **arg_v = &argv[1];
    int all = 0, help = 0;
    char *name = RT_NULL;

    while(arg_c > 0){
        if(strcmp(arg_v[0], "-a") == 0){
            all = 1;
        } else if(strcmp(arg_v[0], "-h") == 0){
            help = 1;
        }else{
            name = arg_v[0];
        }
        arg_c--; arg_v++;
    }

    if (help == 1) {
        printObjectUsage(argv[0]);
        return 0;
    }
    if (all == 1) {
        return od_all_sem();
    }

    return od_sem(name);
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(cmd_od_sem, od_sem, dump semaphore);
#endif
#endif

#ifdef RT_USING_EVENT
int od_event(char *name)
{
    unsigned int start_addr = 0, end_addr = 0;

    const char *item_title = "event";
    struct rt_object_information *info;
    rt_list_t *list;
    struct rt_object *obj;
    struct rt_event *event;
    struct rt_list_node *prev, *next;

    if (name == RT_NULL) {
        rt_kprintf("%-*.s      addr       set\n", RT_NAME_MAX, item_title);
        object_split(RT_NAME_MAX);
        rt_kprintf(" | ---------- | -----\n");

        info = rt_object_get_information(RT_Object_Class_Event);
        list = &info->object_list;

        rt_list_for_each_safe(prev, next, list) {
            obj = rt_list_entry(prev, struct rt_object, list);
            event = (struct rt_event *)obj;
            rt_kprintf("%-*.*s   0x%08X   %5d\n", RT_NAME_MAX, RT_NAME_MAX, 
                        event->parent.parent.name, event, event->set);
        }
        return 0;
    }

    event = (struct rt_event *)rt_object_find(name, RT_Object_Class_Event);
    if (event == RT_NULL) {
        rt_kprintf("event %s not found\n", name);
        return -1;
    }

    start_addr = (unsigned int)event;
    end_addr = start_addr + sizeof(struct rt_event) - 1;
    printMem(start_addr, end_addr, group_size, line_size);
    rt_kprintf("\n");

    rt_kprintf("name:           %s\n", event->parent.parent.name);
    rt_kprintf("  type:         0x%02X\n", event->parent.parent.type);
    rt_kprintf("  flag:         0x%02X\n", event->parent.parent.flag);
    rt_kprintf("  prev object:  %P\n", event->parent.parent.list.prev);
    rt_kprintf("  next object:  %P\n", event->parent.parent.list.next);
    rt_kprintf("  prev suspend: %P\n", event->parent.suspend_thread.prev);
    rt_kprintf("  next suspend: %P\n", event->parent.suspend_thread.next);
    rt_kprintf("  set:          0x%08X\n", event->set);

    return 0;
}

int od_all_event()
{
    struct rt_object_information *info;
    rt_list_t *header, *list;
    struct rt_object *obj;
    struct rt_list_node *prev, *next;
    struct rt_event *event, *event_t;
    struct rt_thread *thread_t;
    
    info = rt_object_get_information(RT_Object_Class_Event);
    header = &info->object_list;

    rt_kprintf("class:         Event\n");
    rt_kprintf("header:        %P\n", header);
    rt_kprintf("\n");

    list = header;
    rt_list_for_each_safe(prev, next, list) {
        obj = rt_list_entry(prev, struct rt_object, list);
        event = (struct rt_event *)obj;
        rt_kprintf("event:          %P : %s\n", event, event->parent.parent.name);
        rt_kprintf("  type:         0x%02X : %s\n", event->parent.parent.type, (event->parent.parent.type & RT_Object_Class_Static) ? "static" : "dynamic");
        rt_kprintf("  flag:         0x%02X : %s\n", event->parent.parent.flag, (event->parent.parent.flag & RT_EVENT_FLAG_AND) ? "and" : ((event->parent.parent.flag & RT_EVENT_FLAG_OR) ? "or" : "none"));

        event_t = (struct rt_event *)((unsigned int)event->parent.parent.list.prev - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (event->parent.parent.list.prev == header) {
        rt_kprintf("  prev event:   %P : %s\n", header, "none");
        } else {
        rt_kprintf("  prev event:   %P : %s\n", event_t, event_t->parent.parent.name);
        }

        event_t = (struct rt_event *)((unsigned int)event->parent.parent.list.next - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (event->parent.parent.list.next == header) {
        rt_kprintf("  next event:   %P : %s\n", header, "none");
        } else {
        rt_kprintf("  next event:   %P : %s\n", event_t, event_t->parent.parent.name);
        }

        if (event->parent.suspend_thread.prev != &event->parent.suspend_thread) {
        thread_t = (struct rt_thread *)((unsigned int)event->parent.suspend_thread.prev - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  prev suspend: %P : %s\n", thread_t, thread_t->name);
        }
        if (event->parent.suspend_thread.next != &event->parent.suspend_thread) {
        thread_t = (struct rt_thread *)((unsigned int)event->parent.suspend_thread.next - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  next suspend: %P : %s\n", thread_t, thread_t->name);
        }
        rt_kprintf("  set:          0x%08X\n", event->set);
        rt_kprintf("\n");
    }
    return 0;
}

static int cmd_od_event(int argc, char *argv[])
{
    int arg_c = argc-1;
    char **arg_v = &argv[1];
    int all = 0, help = 0;
    char *name = RT_NULL;

    while(arg_c > 0){
        if(strcmp(arg_v[0], "-a") == 0){
            all = 1;
        } else if(strcmp(arg_v[0], "-h") == 0){
            help = 1;
        }else{
            name = arg_v[0];
        }
        arg_c--; arg_v++;
    }

    if (help == 1) {
        printObjectUsage(argv[0]);
        return 0;
    }
    if (all == 1) {
        return od_all_event();
    }

    return od_event(name);
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(cmd_od_event, od_event, dump event);
#endif
#endif

#ifdef RT_USING_MUTEX
int od_mutex(char *name)
{
    unsigned int start_addr = 0, end_addr = 0;

    const char *item_title = "mutex";
    struct rt_object_information *info;
    rt_list_t *list;
    struct rt_object *obj;
    struct rt_mutex *mutex;
    struct rt_list_node *prev, *next;

    if (name == RT_NULL) {
        rt_kprintf("%-*.s      addr        owner    hold\n", RT_NAME_MAX, item_title);
        object_split(RT_NAME_MAX);
        rt_kprintf(" | ---------- | ---------- | -----\n");

        info = rt_object_get_information(RT_Object_Class_Mutex);
        list = &info->object_list;

        rt_list_for_each_safe(prev, next, list) {
            obj = rt_list_entry(prev, struct rt_object, list);
            mutex = (struct rt_mutex *)obj;
            rt_kprintf("%-*.*s   0x%08X   0x%08X   %5d\n", RT_NAME_MAX, RT_NAME_MAX, 
                        mutex->parent.parent.name, mutex, mutex->owner, mutex->hold);
        }
        return 0;
    }

    mutex = (struct rt_mutex *)rt_object_find(name, RT_Object_Class_Mutex);
    if (mutex == RT_NULL) {
        rt_kprintf("mutex %s not found\n", name);
        return -1;
    }

    start_addr = (unsigned int)mutex;
    end_addr = start_addr + sizeof(struct rt_mutex) - 1;
    printMem(start_addr, end_addr, group_size, line_size);
    rt_kprintf("\n");

    rt_kprintf("name:           %s\n", mutex->parent.parent.name);
    rt_kprintf("  type:         0x%02X\n", mutex->parent.parent.type);
    rt_kprintf("  flag:         0x%02X\n", mutex->parent.parent.flag);
    rt_kprintf("  prev object:  %P\n", mutex->parent.parent.list.prev);
    rt_kprintf("  next object:  %P\n", mutex->parent.parent.list.next);
    rt_kprintf("  prev suspend: %P\n", mutex->parent.suspend_thread.prev);
    rt_kprintf("  next suspend: %P\n", mutex->parent.suspend_thread.next);
//    rt_kprintf("  value:        %d\n", mutex->value);
    rt_kprintf("  orig prior:   0x%02X\n", mutex->original_priority);
    rt_kprintf("  hold:         %d\n", mutex->hold);
    rt_kprintf("  owner:        %P\n", mutex->owner);

    return 0;
}

int od_all_mutex()
{
    struct rt_object_information *info;
    rt_list_t *header, *list;
    struct rt_object *obj;
    struct rt_list_node *prev, *next;
    struct rt_mutex *mutex, *mutex_t;
    struct rt_thread *thread_t;

    info = rt_object_get_information(RT_Object_Class_Mutex);
    header = &info->object_list;

    rt_kprintf("class:         Mutex\n");
    rt_kprintf("header:        %P\n", header);
    rt_kprintf("\n");

    list = header;
    rt_list_for_each_safe(prev, next, list) {
        obj = rt_list_entry(prev, struct rt_object, list);
        mutex = (struct rt_mutex *)obj;
        rt_kprintf("mutex:          %P : %s\n", mutex, mutex->parent.parent.name);
        rt_kprintf("  type:         0x%02X : %s\n", mutex->parent.parent.type, (mutex->parent.parent.type & RT_Object_Class_Static) ? "static" : "dynamic");
        rt_kprintf("  flag:         0x%02X : %s\n", mutex->parent.parent.flag, (mutex->parent.parent.flag & RT_IPC_FLAG_PRIO) ? "PRIO" : "FIFO");

        mutex_t = (struct rt_mutex *)((unsigned int)mutex->parent.parent.list.prev - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (mutex->parent.parent.list.prev == header) {
        rt_kprintf("  prev mutex:   %P : %s\n", header, "none");
        } else {
        rt_kprintf("  prev mutex:   %P : %s\n", mutex_t, mutex_t->parent.parent.name);
        }
        mutex_t = (struct rt_mutex *)((unsigned int)mutex->parent.parent.list.next - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (mutex->parent.parent.list.next == header) {
        rt_kprintf("  next mutex:   %P : %s\n", header, "none");
        } else {
        rt_kprintf("  next mutex:   %P : %s\n", mutex_t, mutex_t->parent.parent.name);
        }

        if (mutex->parent.suspend_thread.prev != &mutex->parent.suspend_thread) {
        thread_t = (struct rt_thread *)((unsigned int)mutex->parent.suspend_thread.prev - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  prev suspend: %P : %s\n", thread_t, thread_t->name);
        }
        if (mutex->parent.suspend_thread.next != &mutex->parent.suspend_thread) {
        thread_t = (struct rt_thread *)((unsigned int)mutex->parent.suspend_thread.next - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  next suspend: %P : %s\n", thread_t, thread_t->name);
        }

//        rt_kprintf("  value:        %d\n", mutex->value);
        rt_kprintf("  orig prior:   0x%02X\n", mutex->original_priority);
        rt_kprintf("  hold:         %d\n", mutex->hold);
        if (mutex->owner != RT_NULL) {
        rt_kprintf("  owner:        %P\n", mutex->owner, mutex->owner->name);
        }
        rt_kprintf("\n");
    }
    return 0;
}

static int cmd_od_mutex(int argc, char *argv[])
{
    int arg_c = argc-1;
    char **arg_v = &argv[1];
    int all = 0, help = 0;
    char *name = RT_NULL;

    while(arg_c > 0){
        if(strcmp(arg_v[0], "-a") == 0){
            all = 1;
        } else if(strcmp(arg_v[0], "-h") == 0){
            help = 1;
        }else{
            name = arg_v[0];
        }
        arg_c--; arg_v++;
    }

    if (help == 1) {
        printObjectUsage(argv[0]);
        return 0;
    }
    if (all == 1) {
        return od_all_mutex();
    }

    return od_mutex(name);
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(cmd_od_mutex, od_mutex, dump mutex);
#endif
#endif

#ifdef RT_USING_MAILBOX
int od_mailbox(char *name)
{
    unsigned int start_addr = 0, end_addr = 0;

    const char *item_title = "mailbox";
    struct rt_object_information *info;
    rt_list_t *list;
    struct rt_object *obj;
    struct rt_mailbox *mb;
    struct rt_list_node *prev, *next;

    if (name == RT_NULL) {
        rt_kprintf("%-*.s      addr         pool      size    entry    in      out\n", RT_NAME_MAX, item_title);
        object_split(RT_NAME_MAX);
        rt_kprintf(" | ---------- | ---------- | ----- | ----- | ----- | -----\n");

        info = rt_object_get_information(RT_Object_Class_MailBox);
        list = &info->object_list;

        rt_list_for_each_safe(prev, next, list) {
            obj = rt_list_entry(prev, struct rt_object, list);
            mb = (struct rt_mailbox *)obj;
            rt_kprintf("%-*.*s   0x%08X   0x%08X   %5d   %5d   %5d   %5d\n", RT_NAME_MAX, RT_NAME_MAX, 
                        mb->parent.parent.name, mb, mb->msg_pool, mb->size, mb->entry, mb->in_offset, mb->out_offset);
        }
        return 0;
    }

    mb = (struct rt_mailbox *)rt_object_find(name, RT_Object_Class_MailBox);
    if (mb == RT_NULL) {
        rt_kprintf("mailbox %s not found\n", name);
        return -1;
    }

    start_addr = (unsigned int)mb;
    end_addr = start_addr + sizeof(struct rt_mailbox) - 1;
    printMem(start_addr, end_addr, group_size, line_size);
    rt_kprintf("\n");

    rt_kprintf("name:           %s\n", mb->parent.parent.name);
    rt_kprintf("  type:         0x%02X\n", mb->parent.parent.type);
    rt_kprintf("  flag:         0x%02X\n", mb->parent.parent.flag);
    rt_kprintf("  prev object:  %P\n", mb->parent.parent.list.prev);
    rt_kprintf("  next object:  %P\n", mb->parent.parent.list.next);
    rt_kprintf("  prev suspend: %P\n", mb->parent.suspend_thread.prev);
    rt_kprintf("  next suspend: %P\n", mb->parent.suspend_thread.next);
    rt_kprintf("  pool:         %P\n", mb->msg_pool);
    rt_kprintf("  size:         %d\n", mb->size);
    rt_kprintf("  entry:        %d\n", mb->entry);
    rt_kprintf("  in:           %d\n", mb->in_offset);
    rt_kprintf("  out:          %d\n", mb->out_offset);
    rt_kprintf("  prev sender:  %P\n", mb->suspend_sender_thread.prev);
    rt_kprintf("  next sender:  %P\n", mb->suspend_sender_thread.next);

    return 0;
}

int od_all_mailbox()
{
    struct rt_object_information *info;
    rt_list_t *header, *list;
    struct rt_object *obj;
    struct rt_list_node *prev, *next;
    struct rt_mailbox *mb, *mb_t;
    struct rt_thread *thread_t;

    info = rt_object_get_information(RT_Object_Class_MailBox);
    header = &info->object_list;

    rt_kprintf("class:         Mail Box\n");
    rt_kprintf("header:        %P\n", header);
    rt_kprintf("\n");

    list = header;
    rt_list_for_each_safe(prev, next, list) {
        obj = rt_list_entry(prev, struct rt_object, list);
        mb = (struct rt_mailbox *)obj;
        rt_kprintf("mail box:       %P : %s\n", mb, mb->parent.parent.name);
        rt_kprintf("  type:         0x%02X : %s\n", mb->parent.parent.type, (mb->parent.parent.type & RT_Object_Class_Static) ? "static" : "dynamic");
        rt_kprintf("  flag:         0x%02X : %s\n", mb->parent.parent.flag, (mb->parent.parent.flag & RT_IPC_FLAG_PRIO) ? "PRIO" : "FIFO");

        mb_t = (struct rt_mailbox *)((unsigned int)mb->parent.parent.list.prev - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (mb->parent.parent.list.prev == header) {
        rt_kprintf("  prev mb:      %P : %s\n", header, "none");
        } else {
        rt_kprintf("  prev mb:      %P : %s\n", mb_t, mb_t->parent.parent.name);
        }
        mb_t = (struct rt_mailbox *)((unsigned int)mb->parent.parent.list.next - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (mb->parent.parent.list.next == header) {
        rt_kprintf("  next mb:      %P : %s\n", header, "none");
        } else {
        rt_kprintf("  next mb:      %P : %s\n", mb_t, mb_t->parent.parent.name);
        }

        if (mb->parent.suspend_thread.prev != &mb->parent.suspend_thread) {
        thread_t = (struct rt_thread *)((unsigned int)mb->parent.suspend_thread.prev - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  prev suspend: %P : %s\n", thread_t, thread_t->name);
        }
        if (mb->parent.suspend_thread.next != &mb->parent.suspend_thread) {
        thread_t = (struct rt_thread *)((unsigned int)mb->parent.suspend_thread.next - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  next suspend: %P : %s\n", thread_t, thread_t->name);
        }

        if (mb->suspend_sender_thread.prev != &mb->suspend_sender_thread) {
        thread_t = (struct rt_thread *)((unsigned int)mb->suspend_sender_thread.prev - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  prev sender:  %P : %s\n", thread_t, thread_t->name);
        }
        if (mb->suspend_sender_thread.next != &mb->suspend_sender_thread) {
        thread_t = (struct rt_thread *)((unsigned int)mb->suspend_sender_thread.next - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  next sender:  %P : %s\n", thread_t, thread_t->name);
        }

        rt_kprintf("  pool:         %P\n", mb->msg_pool);
        rt_kprintf("  size:         %d\n", mb->size);
        rt_kprintf("  entry:        %d\n", mb->entry);
        rt_kprintf("  in:           %d\n", mb->in_offset);
        rt_kprintf("  out:          %d\n", mb->out_offset);
        rt_kprintf("\n");
    }
    return 0;
}

static int cmd_od_mailbox(int argc, char *argv[])
{
    int arg_c = argc-1;
    char **arg_v = &argv[1];
    int all = 0, help = 0;
    char *name = RT_NULL;

    while(arg_c > 0){
        if(strcmp(arg_v[0], "-a") == 0){
            all = 1;
        } else if(strcmp(arg_v[0], "-h") == 0){
            help = 1;
        }else{
            name = arg_v[0];
        }
        arg_c--; arg_v++;
    }

    if (help == 1) {
        printObjectUsage(argv[0]);
        return 0;
    }
    if (all == 1) {
        return od_all_mailbox();
    }

    return od_mailbox(name);
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(cmd_od_mailbox, od_mailbox, dump mail box);
#endif
#endif

#ifdef RT_USING_MESSAGEQUEUE
int od_msgqueue(char *name)
{
    unsigned int start_addr = 0, end_addr = 0;

    const char *item_title = "msgqueue";
    struct rt_object_information *info;
    rt_list_t *list;
    struct rt_object *obj;
    struct rt_messagequeue *mq;
    struct rt_list_node *prev, *next;

    if (name == RT_NULL) {
        rt_kprintf("%-*.s      addr        pool       size     max\n", RT_NAME_MAX, item_title);
        object_split(RT_NAME_MAX);
        rt_kprintf(" | ---------- | ---------- | ----- | ----- | -----\n");

        info = rt_object_get_information(RT_Object_Class_MessageQueue);
        list = &info->object_list;

        rt_list_for_each_safe(prev, next, list) {
            obj = rt_list_entry(prev, struct rt_object, list);
            mq = (struct rt_messagequeue *)obj;
            rt_kprintf("%-*.*s   0x%08X   0x%08X   %5d   %5d   %5d\n", RT_NAME_MAX, RT_NAME_MAX, 
                        mq->parent.parent.name, mq, mq->msg_pool, mq->msg_size, mq->max_msgs);
        }
        return 0;
    }

    mq = (struct rt_messagequeue *)rt_object_find(name, RT_Object_Class_MessageQueue);
    if (mq == RT_NULL) {
        rt_kprintf("msgqueue %s not found\n", name);
        return -1;
    }

    start_addr = (unsigned int)mq;
    end_addr = start_addr + sizeof(struct rt_messagequeue) - 1;
    printMem(start_addr, end_addr, group_size, line_size);
    rt_kprintf("\n");

    rt_kprintf("name:           %s\n", mq->parent.parent.name);
    rt_kprintf("  type:         0x%02X\n", mq->parent.parent.type);
    rt_kprintf("  flag:         0x%02X\n", mq->parent.parent.flag);
    rt_kprintf("  prev object:  %P\n", mq->parent.parent.list.prev);
    rt_kprintf("  next object:  %P\n", mq->parent.parent.list.next);
    rt_kprintf("  prev suspend: %P\n", mq->parent.suspend_thread.prev);
    rt_kprintf("  next suspend: %P\n", mq->parent.suspend_thread.next);
    rt_kprintf("  pool:         %P\n", mq->msg_pool);
    rt_kprintf("  size:         %d\n", mq->msg_size);
    rt_kprintf("  max msgs:     %d\n", mq->max_msgs);
    rt_kprintf("  head:         %P\n", mq->msg_queue_head);
    rt_kprintf("  tail:         %P\n", mq->msg_queue_tail);
    rt_kprintf("  free:         %P\n", mq->msg_queue_free);
    rt_kprintf("  prev sender:  %P\n", mq->suspend_sender_thread.prev);
    rt_kprintf("  next sender:  %P\n", mq->suspend_sender_thread.next);

    return 0;
}

int od_all_msgqueue()
{
    struct rt_object_information *info;
    rt_list_t *header, *list;
    struct rt_object *obj;
    struct rt_list_node *prev, *next;
    struct rt_messagequeue *mq, *mq_t;
    struct rt_thread *thread_t;
    unsigned int start_addr = 0, end_addr = 0;
    int i;

    info = rt_object_get_information(RT_Object_Class_MessageQueue);
    header = &info->object_list;

    rt_kprintf("class:         MessageQueue\n");
    rt_kprintf("header:        %P\n", header);
    rt_kprintf("\n");

    list = header;
    rt_list_for_each_safe(prev, next, list) {
        obj = rt_list_entry(prev, struct rt_object, list);
        mq = (struct rt_messagequeue *)obj;
        rt_kprintf("message queue:  %P : %s\n", mq, mq->parent.parent.name);
        rt_kprintf("  type:         0x%02X : %s\n", mq->parent.parent.type, (mq->parent.parent.type & RT_Object_Class_Static) ? "static" : "dynamic");
        rt_kprintf("  flag:         0x%02X : %s\n", mq->parent.parent.flag, (mq->parent.parent.flag & RT_IPC_FLAG_PRIO) ? "PRIO" : "FIFO");

        mq_t = (struct rt_messagequeue *)((unsigned int)mq->parent.parent.list.prev - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (mq->parent.parent.list.prev == header) {
        rt_kprintf("  prev mq:      %P : %s\n", header, "none");
        } else {
        rt_kprintf("  prev mq:      %P : %s\n", mq_t, mq_t->parent.parent.name);
        }
        mq_t = (struct rt_messagequeue *)((unsigned int)mq->parent.parent.list.next - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (mq->parent.parent.list.next == header) {
        rt_kprintf("  next mq:      %P : %s\n", header, "none");
        } else {
        rt_kprintf("  next mq:      %P : %s\n", mq_t, mq_t->parent.parent.name);
        }

        if (mq->parent.suspend_thread.prev != &mq->parent.suspend_thread) {
        thread_t = (struct rt_thread *)((unsigned int)mq->parent.suspend_thread.prev - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  prev suspend: %P : %s\n", thread_t, thread_t->name);
        }
        if (mq->parent.suspend_thread.next != &mq->parent.suspend_thread) {
        thread_t = (struct rt_thread *)((unsigned int)mq->parent.suspend_thread.next - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  next suspend: %P : %s\n", thread_t, thread_t->name);
        }

        if (mq->suspend_sender_thread.prev != &mq->suspend_sender_thread) {
        thread_t = (struct rt_thread *)((unsigned int)mq->suspend_sender_thread.prev - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  prev sender:  %P : %s\n", thread_t, thread_t->name);
        }
        if (mq->suspend_sender_thread.next != &mq->suspend_sender_thread) {
        thread_t = (struct rt_thread *)((unsigned int)mq->suspend_sender_thread.next - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  next sender:  %P : %s\n", thread_t, thread_t->name);
        }

        rt_kprintf("  pool:         %P\n", mq->msg_pool);
        rt_kprintf("  size:         %d\n", mq->msg_size);
        rt_kprintf("  max msgs:     %d\n", mq->max_msgs);
        rt_kprintf("  head:         %P\n", mq->msg_queue_head);
        rt_kprintf("  tail:         %P\n", mq->msg_queue_tail);
        rt_kprintf("  free:         %P\n", mq->msg_queue_free);

        rt_kprintf("\n");
        for (i = 0; i < mq->max_msgs; i++ ) {
        rt_kprintf("    msg %02d: ", i+1);
        start_addr = (unsigned int)mq->msg_pool + (mq->msg_size + sizeof(void *)) * i;
        end_addr = start_addr + mq->msg_size + sizeof(void *) -1;
        printMem(start_addr, end_addr, group_size, line_size);
        }
        rt_kprintf("\n");
    }
    return 0;
}

static int cmd_od_msgqueue(int argc, char *argv[])
{
    int arg_c = argc-1;
    char **arg_v = &argv[1];
    int all = 0, help = 0;
    char *name = RT_NULL;

    while(arg_c > 0){
        if(strcmp(arg_v[0], "-a") == 0){
            all = 1;
        } else if(strcmp(arg_v[0], "-h") == 0){
            help = 1;
        }else{
            name = arg_v[0];
        }
        arg_c--; arg_v++;
    }

    if (help == 1) {
        printObjectUsage(argv[0]);
        return 0;
    }
    if (all == 1) {
        return od_all_msgqueue();
    }

    return od_msgqueue(name);
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(cmd_od_msgqueue, od_msgqueue, dump message queue);
#endif
#endif

#ifdef RT_USING_MEMHEAP
/* dynamic pool magic and mask */
#define RT_MEMHEAP_MAGIC        0x1ea01ea0
#define RT_MEMHEAP_MASK         0xfffffffe
#define RT_MEMHEAP_USED         0x01
#define RT_MEMHEAP_FREED        0x00

int od_memheap(char *name)
{
    unsigned int start_addr = 0, end_addr = 0;

    const char *item_title = "memheap";
    struct rt_object_information *info;
    rt_list_t *list;
    struct rt_object *obj;
    struct rt_memheap *mh;
    struct rt_list_node *prev, *next;

    if (name == RT_NULL) {
        rt_kprintf("%-*.s      addr        size     max used    total\n", RT_NAME_MAX, item_title);
        object_split(RT_NAME_MAX);
        rt_kprintf(" | ---------- | -------- | -------- | --------\n");

        info = rt_object_get_information(RT_Object_Class_MemHeap);
        list = &info->object_list;

        rt_list_for_each_safe(prev, next, list) {
            obj = rt_list_entry(prev, struct rt_object, list);
            mh = (struct rt_memheap *)obj;
            rt_kprintf("%-*.*s   0x%08X   %8d   %8d   %8d\n", RT_NAME_MAX, RT_NAME_MAX, 
                        mh->parent.name, mh, mh->pool_size, mh->max_used_size, mh->available_size);
        }
        return 0;
    }

    mh = (struct rt_memheap *)rt_object_find(name, RT_Object_Class_MemHeap);
    if (mh == RT_NULL) {
        rt_kprintf("memheap %s not found\n", name);
        return -1;
    }

    start_addr = (unsigned int)mh;
    end_addr = start_addr + sizeof(struct rt_memheap) - 1;
    printMem(start_addr, end_addr, group_size, line_size);
    rt_kprintf("\n");

    rt_kprintf("name:           %s\n", mh->parent.name);
    rt_kprintf("  type:         0x%02X\n", mh->parent.type);
    rt_kprintf("  flag:         0x%02X\n", mh->parent.flag);
    rt_kprintf("  prev object:  %P\n", mh->parent.list.prev);
    rt_kprintf("  next object:  %P\n", mh->parent.list.next);
    rt_kprintf("  start addr:   %P\n", mh->start_addr);
    rt_kprintf("  pool size:    %d / %dk\n", mh->pool_size, mh->pool_size/1024);
    rt_kprintf("  available:    %d / %dk\n", mh->available_size, mh->available_size/1024);
    rt_kprintf("  max used:     %d\n", mh->max_used_size);
    rt_kprintf("  lock:         %s\n", mh->lock.parent.parent.name);
    rt_kprintf("  item header:  %P\n", &mh->free_header);
    rt_kprintf("  item used:    %P\n", mh->block_list);
    rt_kprintf("  item free:    %P\n", mh->free_list);

    return 0;
}

int od_all_memheap()
{
    struct rt_object_information *info;
    rt_list_t *header, *list;
    struct rt_object *obj;
    struct rt_list_node *prev, *next;
    struct rt_memheap *mh, *mh_t;
    struct rt_memheap_item *mhi;
    
    info = rt_object_get_information(RT_Object_Class_MemHeap);
    header = &info->object_list;

    rt_kprintf("class:         MemHeap\n");
    rt_kprintf("header:        %P\n", header);
    rt_kprintf("\n");

    list = header;
    rt_list_for_each_safe(prev, next, list) {
        obj = rt_list_entry(prev, struct rt_object, list);
        mh = (struct rt_memheap *)obj;
        rt_kprintf("memory heap:    %P : %s\n", mh, mh->parent.name);
        rt_kprintf("  type:         0x%02X : %s\n", mh->parent.type, (mh->parent.type & RT_Object_Class_Static) ? "static" : "dynamic");

        mh_t = (struct rt_memheap *)((unsigned int)mh->parent.list.prev - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (mh->parent.list.prev == header) {
        rt_kprintf("  prev heap:    %P : %s\n", header, "none");
        } else {
        rt_kprintf("  prev heap:    %P : %s\n", mh_t, mh_t->parent.name);
        }
        mh_t = (struct rt_memheap *)((unsigned int)mh->parent.list.next - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (mh->parent.list.next == header) {
        rt_kprintf("  next heap:    %P : %s\n", header, "none");
        } else {
        rt_kprintf("  next heap:    %P : %s\n", mh_t, mh_t->parent.name);
        }

        rt_kprintf("  start addr:   %P\n", mh->start_addr);
        rt_kprintf("  pool size:    %d / %dk\n", mh->pool_size, mh->pool_size/1024);
        rt_kprintf("  available:    %d / %dk\n", mh->available_size, mh->available_size/1024);
        rt_kprintf("  max used:     %d\n", mh->max_used_size);
        rt_kprintf("  lock:         %s\n", mh->lock.parent.parent.name);
        rt_kprintf("  item header:  %P\n", &mh->free_header);
        rt_kprintf("  item used:    %P\n", mh->block_list);
        rt_kprintf("  item free:    %P\n", mh->free_list);

        mhi = &mh->free_header;
        rt_kprintf("\n");
        rt_kprintf("    header:       %P\n", mhi);
        rt_kprintf("      magic:      0x%08X : %s \n", mhi->magic, (mhi->magic & RT_MEMHEAP_USED) ? "used" : "freed");
        rt_kprintf("      pool:       %P\n", mhi->pool_ptr);
        rt_kprintf("      prev item:  %P\n", mhi->prev);
        rt_kprintf("      next item:  %P\n", mhi->next);
        rt_kprintf("      prev free:  %P\n", mhi->prev_free);
        rt_kprintf("      next free:  %P\n", mhi->next_free);

        mhi = mh->block_list;
        rt_kprintf("\n    used block list:\n");
        rt_kprintf("      ----------------------------------------\n");
        do {
        rt_kprintf("      item:       %P\n", mhi);
        rt_kprintf("      magic:      0x%08X : %s \n", mhi->magic, (mhi->magic & RT_MEMHEAP_USED) ? "used" : "freed");
        rt_kprintf("      pool:       %P\n", mhi->pool_ptr);
        rt_kprintf("      prev item:  %P\n", mhi->prev);
        rt_kprintf("      next item:  %P\n", mhi->next);
        rt_kprintf("      prev free:  %P\n", mhi->prev_free);
        rt_kprintf("      next free:  %P\n", mhi->next_free);
        rt_kprintf("      ----------------------------------------\n");
        if ((mhi-> magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC) {
            mhi = mhi->next;
        } else {
            rt_kprintf("\n    Maybe Error heap!!!\n");
            break;
        }
        } while(mhi != RT_NULL && mhi != mh->block_list);

        mhi = mh->free_list;
        rt_kprintf("\n    free block list:\n");
        rt_kprintf("      ----------------------------------------\n");
        do {
        rt_kprintf("      item:       %P\n", mhi);
        rt_kprintf("      magic:      0x%08X : %s \n", mhi->magic, (mhi->magic & RT_MEMHEAP_USED) ? "used" : "freed");
        rt_kprintf("      pool:       %P\n", mhi->pool_ptr);
        rt_kprintf("      prev item:  %P\n", mhi->prev);
        rt_kprintf("      next item:  %P\n", mhi->next);
        rt_kprintf("      prev free:  %P\n", mhi->prev_free);
        rt_kprintf("      next free:  %P\n", mhi->next_free);
        rt_kprintf("      ----------------------------------------\n");
        if ((mhi-> magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC) {
            mhi = mhi->next;
        } else {
            rt_kprintf("\n    Maybe Error heap!!!\n");
            break;
        }
        } while(mhi != RT_NULL && mhi != mh->free_list);
        rt_kprintf("\n");
    }
    return 0;
}

static int cmd_od_memheap(int argc, char *argv[])
{
    int arg_c = argc-1;
    char **arg_v = &argv[1];
    int all = 0, help = 0;
    char *name = RT_NULL;

    while(arg_c > 0){
        if(strcmp(arg_v[0], "-a") == 0){
            all = 1;
        } else if(strcmp(arg_v[0], "-h") == 0){
            help = 1;
        }else{
            name = arg_v[0];
        }
        arg_c--; arg_v++;
    }

    if (help == 1) {
        printObjectUsage(argv[0]);
        return 0;
    }
    if (all == 1) {
        return od_all_memheap();
    }

    return od_memheap(name);
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(cmd_od_memheap, od_memheap, dump memory heap);
#endif

int od_memheap_item(unsigned int start_addr)
{
    unsigned int end_addr = 0;
    struct rt_memheap_item *mhi;

    mhi = (struct rt_memheap_item *)start_addr;

    end_addr = start_addr + sizeof(struct rt_memheap_item) - 1;
    printMem(start_addr, end_addr, group_size, line_size);
    rt_kprintf("\n");

    rt_kprintf("heap item:      %P\n", mhi);
    rt_kprintf("  magic:        0x%08X\n", mhi->magic);
    rt_kprintf("  pool:         %P\n", mhi->pool_ptr);
    rt_kprintf("  prev item:    %P\n", mhi->prev);
    rt_kprintf("  next item:    %P\n", mhi->next);
    rt_kprintf("  prev free:    %P\n", mhi->prev_free);
    rt_kprintf("  next free:    %P\n", mhi->next_free);
#ifdef RT_USING_MEMTRACE
    rt_kprintf("  owner:        %c%c%c%c\n", mhi->owner_thread_name[0], mhi->owner_thread_name[1], mhi->owner_thread_name[2], mhi->owner_thread_name[3]);
#endif

    return 0;
}

static int cmd_od_memheap_item(int argc, char *argv[])
{
    int arg_c = argc-1;
    char **arg_v = &argv[1];
    char *_start = 0;
    unsigned int start_addr = 0;
    int i;

    if(arg_c == 0){
        rt_kprintf("Input a memheap item address!\n");
        return -1;
    }

    _start = arg_v[0];
    if (_start[0] == '0' && (_start[1] == 'x' || _start[1] == 'X')) {
        _start += 2;
    }
    start_addr = 0;
    for (i = 0; i < strlen(_start); i++) {
        start_addr <<= 4;
        if (!isxdigit(_start[i])) {
            rt_kprintf("Invalide memheap item address!\n");
            return -1;
        }
        start_addr |= tohex(toupper(_start[i]));
    }

    return od_memheap_item(start_addr);
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(cmd_od_memheap_item, od_memheap_item, dump memory heap item);
#endif
#endif

#ifdef RT_USING_MEMPOOL
int od_mempool(char *name)
{
    unsigned int start_addr = 0, end_addr = 0;

    const char *item_title = "mempool";
    struct rt_object_information *info;
    rt_list_t *list;
    struct rt_object *obj;
    struct rt_mempool *mp;
    struct rt_list_node *prev, *next;

    if (name == RT_NULL) {
        rt_kprintf("%-*.s      addr        size    block size  total   free\n", RT_NAME_MAX, item_title);
        object_split(RT_NAME_MAX);
        rt_kprintf(" | ---------- | -------- | -------- | ----- | -----\n");

        info = rt_object_get_information(RT_Object_Class_MemPool);
        list = &info->object_list;

        rt_list_for_each_safe(prev, next, list) {
            obj = rt_list_entry(prev, struct rt_object, list);
            mp = (struct rt_mempool *)obj;
            rt_kprintf("%-*.*s   0x%08X   0x%08X   0x%08X   0x%08X\n", RT_NAME_MAX, RT_NAME_MAX, 
                        mp->parent.name, mp, mp->size, mp->block_size, mp->block_total_count, mp->block_free_count);
        }
        return 0;
    }

    mp = (struct rt_mempool *)rt_object_find(name, RT_Object_Class_MemPool);
    if (mp == RT_NULL) {
        rt_kprintf("mempool %s not found\n", name);
        return -1;
    }

    start_addr = (unsigned int)mp;
    end_addr = start_addr + sizeof(struct rt_mempool) - 1;
    printMem(start_addr, end_addr, group_size, line_size);
    rt_kprintf("\n");

    rt_kprintf("name:           %s\n", mp->parent.name);
    rt_kprintf("  type:         0x%02X\n", mp->parent.type);
    rt_kprintf("  flag:         0x%02X\n", mp->parent.flag);
    rt_kprintf("  prev object:  %P\n", mp->parent.list.prev);
    rt_kprintf("  next object:  %P\n", mp->parent.list.next);
    rt_kprintf("  start addr:   %P\n", mp->start_address);
    rt_kprintf("  pool size:    %d\n", mp->size);
    rt_kprintf("  block size:   %d\n", mp->block_size);
    rt_kprintf("  max used:     %d\n", mp->block_total_count);
    rt_kprintf("  lock:         %d\n", mp->block_free_count);
    rt_kprintf("  block list:   %P\n", mp->block_list);
    rt_kprintf("  prev suspend: %P\n", mp->suspend_thread.prev);
    rt_kprintf("  next suspend: %P\n", mp->suspend_thread.next);

    return 0;
}

int od_all_mempool()
{
    struct rt_object_information *info;
    rt_list_t *header, *list;
    struct rt_object *obj;
    struct rt_list_node *prev, *next;
    struct rt_mempool *mp, *mp_t;
    struct rt_thread *thread_t;

    info = rt_object_get_information(RT_Object_Class_MemPool);
    header = &info->object_list;

    rt_kprintf("class:         MemPool\n");
    rt_kprintf("header:        %P\n", header);
    rt_kprintf("\n");

    list = header;
    rt_list_for_each_safe(prev, next, list) {
        obj = rt_list_entry(prev, struct rt_object, list);
        mp = (struct rt_mempool *)obj;
        rt_kprintf("mem pool:       %P : %s\n", mp, mp->parent.name);
        rt_kprintf("  type:         0x%02X : %s\n", mp->parent.type, (mp->parent.type & RT_Object_Class_Static) ? "static" : "dynamic");

        mp_t = (struct rt_mempool *)((unsigned int)mp->parent.list.prev - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (mp->parent.list.prev == header) {
        rt_kprintf("  prev pool:    %P : %s\n", header, "none");
        } else {
        rt_kprintf("  prev pool:    %P : %s\n", mp_t, mp_t->parent.name);
        }
        mp_t = (struct rt_mempool *)((unsigned int)mp->parent.list.next - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (mp->parent.list.next == header) {
        rt_kprintf("  next pool:    %P : %s\n", header, "none");
        } else {
        rt_kprintf("  next pool:    %P : %s\n", mp_t, mp_t->parent.name);
        }

        rt_kprintf("  start addr:   %P\n", mp->start_address);
        rt_kprintf("  pool size:    %d\n", mp->size);
        rt_kprintf("  block size:   %d\n", mp->block_size);
        rt_kprintf("  max used:     %d\n", mp->block_total_count);
        rt_kprintf("  lock:         %d\n", mp->block_free_count);
        rt_kprintf("  block list:   %P\n", mp->block_list);
        if (mp->suspend_thread.prev != &mp->suspend_thread) {
        thread_t = (struct rt_thread *)((unsigned int)mp->suspend_thread.prev - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  prev suspend: %P : %s\n", thread_t, thread_t->name);
        }
        if (mp->suspend_thread.next != &mp->suspend_thread) {
        thread_t = (struct rt_thread *)((unsigned int)mp->suspend_thread.next - (unsigned int)(&((struct rt_thread *)0)->tlist));
        rt_kprintf("  next suspend: %P : %s\n", thread_t, thread_t->name);
        }
        rt_kprintf("\n");
    }
    return 0;
}

static int cmd_od_mempool(int argc, char *argv[])
{
    int arg_c = argc-1;
    char **arg_v = &argv[1];
    int all = 0, help = 0;
    char *name = RT_NULL;

    while(arg_c > 0){
        if(strcmp(arg_v[0], "-a") == 0){
            all = 1;
        } else if(strcmp(arg_v[0], "-h") == 0){
            help = 1;
        }else{
            name = arg_v[0];
        }
        arg_c--; arg_v++;
    }

    if (help == 1) {
        printObjectUsage(argv[0]);
        return 0;
    }
    if (all == 1) {
        return od_all_mempool();
    }

    return od_mempool(name);
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(cmd_od_mempool, od_mempool, dump memory pool);
#endif
#endif

int od_timer(char *name)
{
    unsigned int start_addr = 0, end_addr = 0;
    const char *item_title = "timer";
    struct rt_object_information *info;
    rt_list_t *list;
    struct rt_object *obj;
    struct rt_timer *timer;
    struct rt_list_node *prev, *next;
    int i;

    if (name == RT_NULL) {
        rt_kprintf("%-*.s      addr        init       timeout      flags       callback    parameter\n", RT_NAME_MAX, item_title);
        object_split(RT_NAME_MAX);
        rt_kprintf(" | ---------- | -------- | ---------- | ---------- | ---------- | ----------\n");

        info = rt_object_get_information(RT_Object_Class_Timer);
        list = &info->object_list;

        rt_list_for_each_safe(prev, next, list) {
            obj = rt_list_entry(prev, struct rt_object, list);
            timer = (struct rt_timer *)obj;
            rt_kprintf("%-*.*s   0x%08X     %5d    0x%08X      0x%02X      0x%08X   0x%08X\n", RT_NAME_MAX, RT_NAME_MAX, 
                        timer->parent.name, timer, timer->init_tick, timer->timeout_tick, timer->parent.flag, timer->timeout_func, timer->parameter);
        }

        return 0;
    }

    timer = (struct rt_timer *)rt_object_find(name, RT_Object_Class_Timer);
    if (timer == RT_NULL) {
        rt_kprintf("timer %s not found\n", name);
        return -1;
    }

    start_addr = (unsigned int)timer;
    end_addr = start_addr + sizeof(struct rt_timer) - 1;
    printMem(start_addr, end_addr, group_size, line_size);
    rt_kprintf("\n");

    rt_kprintf("name:          %s\n", timer->parent.name);
    rt_kprintf("  type:        0x%02X\n", timer->parent.type);
    rt_kprintf("  flag:        0x%02X\n", timer->parent.flag);
    rt_kprintf("  prev object: %P\n", timer->parent.list.prev);
    rt_kprintf("  next object: %P\n", timer->parent.list.next);
    for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++) {
    rt_kprintf("  prev timer:  %P\n", timer->row[i].prev);
    rt_kprintf("  next timer:  %P\n", timer->row[i].next);
    }
    rt_kprintf("  callback:    %P\n", timer->timeout_func);
    rt_kprintf("  parameter:   %P\n", timer->parameter);
    rt_kprintf("  init tick:   0x%08X\n", timer->init_tick);
    rt_kprintf("  timeout:     0x%08X\n", timer->timeout_tick);

    return 0;
}

int od_all_timer()
{
    struct rt_object_information *info;
    rt_list_t *header, *list;
    struct rt_object *obj;
    struct rt_list_node *prev, *next;
    struct rt_timer *timer, *tim_t;

    info = rt_object_get_information(RT_Object_Class_Timer);
    header = &info->object_list;

    rt_kprintf("class:         Timer\n");
    rt_kprintf("header:        %P\n", header);
    rt_kprintf("\n");

    list = header;
    rt_list_for_each_safe(prev, next, list) {
        obj = rt_list_entry(prev, struct rt_object, list);
        timer = (struct rt_timer *)obj;
        rt_kprintf("timer:         %P : %s\n", timer, timer->parent.name);
        rt_kprintf("  type:        0x%02X : %s\n", timer->parent.type, (timer->parent.type & RT_Object_Class_Static) ? "static" : "dynamic");
        rt_kprintf("  flag:        0x%02X : %s | %s | %s\n", timer->parent.flag,
                                                            (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) ? "active" : "deactive",
                                                            (timer->parent.flag & RT_TIMER_FLAG_PERIODIC) ? "periodic" : "one shot", 
                                                            (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER) ? "soft" : "hard");
        tim_t = (struct rt_timer *)((unsigned int)timer->parent.list.prev - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (timer->parent.list.prev == header) {
        rt_kprintf("  prev timer:  %P : %s\n", header, "none");
        } else {
        rt_kprintf("  prev timer:  %P : %s\n", tim_t, tim_t->parent.name);
        }
        tim_t = (struct rt_timer *)((unsigned int)timer->parent.list.next - sizeof(struct rt_object) + sizeof(struct rt_list_node));
        if (timer->parent.list.next == header) {
        rt_kprintf("  next timer:  %P : %s\n", header, "none");
        } else {
        rt_kprintf("  next timer:  %P : %s\n", tim_t, tim_t->parent.name);
        }
        rt_kprintf("  init tick:   0x%08X\n", timer->init_tick);
        rt_kprintf("  timeout:     0x%08X\n", timer->timeout_tick);
        rt_kprintf("\n");
    }

    return 0;
}

static int cmd_od_timer(int argc, char *argv[])
{
    int arg_c = argc-1;
    char **arg_v = &argv[1];
    int all = 0, help = 0;
    char *name = RT_NULL;

    while(arg_c > 0){
        if(strcmp(arg_v[0], "-a") == 0){
            all = 1;
        } else if(strcmp(arg_v[0], "-h") == 0){
            help = 1;
        }else{
            name = arg_v[0];
        }
        arg_c--; arg_v++;
    }

    if (help == 1) {
        printObjectUsage(argv[0]);
        return 0;
    }
    if (all == 1) {
        return od_all_timer();
    }

    return od_timer(name);
}
#ifdef RT_USING_FINSH
MSH_CMD_EXPORT_ALIAS(cmd_od_timer, od_timer, dump timer);
#endif
